//
//  FileTools.swift
//  Library_y
//
//  Created by JC on 2023/6/6.
//

import Foundation
import MobileCoreServices
import UIKit
import CommonCrypto

// 文件缓存路径
public let Documents = NSHomeDirectory() + "/Documents"
public let Library = NSHomeDirectory() + "/Library"
public let Caches = NSHomeDirectory() + "/Library/Caches"
public let SystemData = NSHomeDirectory() + "/SystemData"
public let TmpDir = NSHomeDirectory() + "/tmp"

final public class FileTools {
    
    /// 获取文件名
    /// - Parameter path: 文件路径 /
    /// - Returns: 文件名
    static public func getFileName(_ path: String) -> String {
        guard let index = path.lastIndex(of: "/") else { return "" }
        let p = String(path[index...])
        return p.sliceSuffix("/")
    }
    
    /// 获取文件名的后缀
    /// - Parameter fileName: 文件名
    static public func getFileNameSuffix(_ fileName: String) -> String {
        if let index = fileName.lastIndex(of: ".") {
            return String(fileName[index...])
        } else {
            return ""
        }
    }
    
    // 获取目录下的所有文件
    static public func getAllFilePath(_ dirPath: String) -> [String]? {
        var filePaths = [String]()
        do {
            let array = try FileManager.default.contentsOfDirectory(atPath: dirPath)
            for fileName in array {
                var isDir: ObjCBool = true
                let fullPath = "\(dirPath)/\(fileName)"
                if FileManager.default.fileExists(atPath: fullPath, isDirectory: &isDir) {
                    if !isDir.boolValue {
                        filePaths.append(fullPath)
                    }
                }
            }
        } catch let error as NSError {
            print("get file path error: \(error)")
        }
        return filePaths
    }
    
    // url处理手机路径 -> Data
    static public func processToData(_ url: URL) -> Data? {
        var fileData: Data?
        // 获取文件安全访问权限
        let authozied = url.startAccessingSecurityScopedResource()
        if authozied {
            // 通过文件协调器读取文件地址
            let fileCoordinator = NSFileCoordinator()
            fileCoordinator.coordinate(readingItemAt: url, options: [.withoutChanges], error: nil) { (newUrl) in
                //读取文件协调器提供的新地址里的数据
                fileData = try? Data.init(contentsOf: newUrl, options: [.mappedIfSafe])
            }
        }
        // 停止安全访问权限
        url.stopAccessingSecurityScopedResource()
        return fileData
    }
}

extension FileTools {
    
    static public let fileManager = FileManager.default
    
    // 创建文件夹
    class public func createFolderPath(_ folderN: String) {
        let folderPath = NSHomeDirectory() + "/Documents/" + folderN
        do {
            try FileManager().createDirectory(atPath: folderPath,
                                               withIntermediateDirectories: true,
                                               attributes: nil)
        } catch {
            Log_y.error(error.localizedDescription)
        }
    }
    
    // 创建文件
    class public func createFile(name: String, fileBaseUrl: URL) {
        let file = fileBaseUrl.appendingPathComponent(name)
        let exist = fileManager.fileExists(atPath: file.path)
        if !exist {
            let data = "".data(using: String.Encoding.utf8)
            fileManager.createFile(atPath: file.path,contents: data,attributes: nil)
        }
    }
    
    /// 计算单个文件的大小
    class public func fileSize(path: String) -> Double {
        if fileManager.fileExists(atPath: path) {
            guard let dict = try? fileManager.attributesOfItem(atPath: path) else { return 0.0}
            if let fileSize = dict[FileAttributeKey.size] as? Int {
                return Double(fileSize) / 1024.0 / 1024.0
            }
        }
        return 0.0
    }
    
    /// 计算整个文件夹的大小
    class public func folderSize(path: String) -> Double {
        
        var folderSize: Double = 0
        if fileManager.fileExists(atPath: path) {
            let chilerFiles = fileManager.subpaths(atPath: path)
            for fileName in chilerFiles! {
                let tmpPath = path as NSString
                let fileFullPathName = tmpPath.appendingPathComponent(fileName)
                folderSize += FileTools.fileSize(path: fileFullPathName)
            }
            return folderSize
        }
        return 0
    }
    
    /// 清除文件 同步
    class public func cleanFolder(path: String, complete:() -> ()) {
        let chilerFiles = self.fileManager.subpaths(atPath: path)
        for fileName in chilerFiles! {
            let tmpPath = path as NSString
            let fileFullPathName = tmpPath.appendingPathComponent(fileName)
            if self.fileManager.fileExists(atPath: fileFullPathName) {
                do {
                    try self.fileManager.removeItem(atPath: fileFullPathName)
                } catch _ {
                }
            }
        }
        complete()
    }
    
    /// 清除文件 异步
    class public func cleanFolderAsync(path: String, complete: @escaping () -> ()) {
        DispatchQueue.main.async() {
            let chilerFiles = self.fileManager.subpaths(atPath: path)
            for fileName in chilerFiles! {
                let tmpPath = path as NSString
                let fileFullPathName = tmpPath.appendingPathComponent(fileName)
                if self.fileManager.fileExists(atPath: fileFullPathName) {
                    do {
                        try self.fileManager.removeItem(atPath: fileFullPathName)
                    } catch _ {
                    }
                }
            }
            complete()
        }
    }
}

extension FileTools {
    
    // 根据后缀获取对应的Mime-Type
    static public func mimeType(_ pathExtension: String) -> String {
        if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
                                                           pathExtension as NSString,
                                                           nil)?.takeRetainedValue() {
            if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?
                .takeRetainedValue() {
                return mimetype as String
            }
        }
        // 文件资源类型如果不知道，传万能类型application/octet-stream，服务器会自动解析文件类
        return "application/octet-stream"
    }
}

extension FileTools {
    
    // 获取文件的Md5值的方法如下
    static public func md5File(url: URL, block: BlockSingleStr? = nil) {
        let start = Tools.stamp
        DispatchQueue.global().async {
            let bufferSize = 1024 * 1024
            do {
                // 打开文件
                let file = try FileHandle(forReadingFrom: url)
                defer { file.closeFile() }
                // 初始化内容
                var context = CC_MD5_CTX()
                CC_MD5_Init(&context)
                // 读取文件信息
                while case let data = file.readData(ofLength: bufferSize), data.count > 0 {
                    data.withUnsafeBytes {
                        _ = CC_MD5_Update(&context, $0, CC_LONG(data.count))
                    }
                }
                //计算Md5摘要
                var digest = Data(count: Int(CC_MD5_DIGEST_LENGTH))
                digest.withUnsafeMutableBytes {
                    _ = CC_MD5_Final($0, &context)
                }
                block?(digest.map { String(format: "%02hhx", $0) }.joined())
            } catch {
                block?("")
            }
        }
    }
}
